
import java.util.*;

/**
 * A class representing a roster.
 *
 * A roster is a class which assigns Buses to Services, and then
 * Drivers to these Buses
 *
 * @version 1.1
 */
public class Roster
{
    //The number of days a roster should be generated for
    private static final int ROSTER_DAYS_LENGTH = 7;
    
    //The date the roster starts on
    private Calendar startDate;
    
    private int progress;

    private ControllerInterface interfaceUsed = null;
    

    public Roster()
    {
        this.startDate = Calendar.getInstance();
        if (this.startDate.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY)
            moveToMonday(this.startDate);
        //System.out.println("Generating Roster for: " + Service.calendarToDateString(this.startDate));
    }

    
  
    public int getProgress()
    {
        System.out.println("Progress!");
        return this.progress;
    }

    public Calendar getStartDate()
    {
        return this.startDate;
    }

    
    //Move the date forward to the next monday
    private static void moveToMonday(Calendar current)
    {
        while (current.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY)
            current.add(Calendar.DAY_OF_MONTH, 1);
    }
    
    

    
    public ArrayList<ArrayList<DriverShift>> generateRoster()
    {
        //BusTORoute
        ArrayList<ArrayList<Bus>> returnBuses = assignBuses();
        //Service to Driver
        //System.out.println("\n\n----------------------Assigning DRIVERS ----------------------\n\n");
        ArrayList<ArrayList<DriverShift>> drivers = assignDrivers(returnBuses);

        System.out.println("Done!");


       /* for (int i = 0; i < 7; i++)
        {
            System.out.println("\n\nFOR DAY : " + Service.calendarToString(startDate));
            Iterator<DriverShift> driverIter = drivers.get(i).iterator();
            int drivID = 0;
            int minsInRow = 0;
            int minsPerDay = 0;
            while (driverIter.hasNext())
            {
                DriverShift currentShift = driverIter.next();
                Driver current = currentShift.getDriver();

                System.out.println(current + ", Minutes worked in a week = " + Driver.driverInfo.getMinutesWeek(current));
            }
            
            startDate.add(Calendar.DAY_OF_MONTH, 1);
        }*/

        return drivers;
        //To generate a roster:
        /*
         * 1) Set current day to today
         * 2) Get list of all drivers available today and hours driven this week < 50
         * 3) Get list of all buses available today
         * 4) Select a random driver, assign them to the first bus route
         * 5) Mark this driver as unavailable for the duration of this journey
         * 6) for each other route
         */
         
    }


    private ArrayList<ArrayList<DriverShift>> assignDrivers(ArrayList<ArrayList<Bus>> buses)
    {
        //TODO: assignDrivers()
        Calendar currentDate = (Calendar)this.startDate.clone();
        Calendar endDate = (Calendar)this.startDate.clone();
        ArrayList<ArrayList<DriverShift>> returnShifts = new  ArrayList<ArrayList<DriverShift>>();



        endDate.add(Calendar.DAY_OF_WEEK, 7);
        int index = 0;

        while(currentDate.before(endDate))
        {
          
           /* //An array list containing all the routes in the IBMS
            ArrayList<Route> routes = Route.getRoutes();
           */
            ArrayList<Bus> servicesToday = buses.get(index);
            //Iterate through every day in the week
            ArrayList<DriverShift> driverShifts = new ArrayList<DriverShift>();
            
            Iterator<Bus> busIterator = servicesToday.iterator();
            ArrayList<Driver> driversAvailable = Driver.getAvailableDriversOn(currentDate.getTime());
            while(busIterator.hasNext())
            {
               ArrayList<BusShift> shifts = busIterator.next().getShifts();
               Collections.sort(shifts);



               Iterator<BusShift> shiftsIterator = shifts.iterator();


               while(shiftsIterator.hasNext())
               {
                  
                   
                   Collections.sort(driversAvailable);
                   Driver currentDriver = driversAvailable.get(0);
                   int indexDriver = 1;
                   BusShift currentShift = shiftsIterator.next();
                   //if (currentDriver.getDriverID())
                   //System.out.println("\n\n\nStart: " + Service.calendarToString(currentShift.getStartTime()) + "End Time: " + Service.calendarToString(currentShift.getEndTime()));
                   DriverShift newShift = new DriverShift(currentShift.getStartTime(), 
                                                          currentShift.getEndTime(),
                                                          currentShift,
                                                          currentDriver);
                   while(!currentDriver.addShift(newShift))
                   {
                       indexDriver++;
                       if (indexDriver >= driversAvailable.size())
                           throw new RosterException("Could not assign index: "
                                                    + indexDriver + " as it's greater than or equal to: " + driversAvailable.size());
                       currentDriver = driversAvailable.get(indexDriver);
                       newShift.setDriver(currentDriver);
                   }

                   //if (currentDriver.getDriverID() == 2071)
                    //System.out.println("Assigning: " + currentDriver + " to shift " + newShift + "On day: " + currentDate.get(Calendar.DAY_OF_WEEK));
                   driverShifts.add(newShift);
               }

            }
            index++;
            System.out.println("Rostered drivers for day: " + Service.dayToString(currentDate));
            currentDate.add(Calendar.DAY_OF_WEEK,1);
            returnShifts.add(driverShifts);

            progress += 10 / 1.4;

        }     

        return returnShifts;
    }
    

    /*
     * Assign all buses to services.
     * 1) Calculate start date and end date
     * 2) Iterate through these dates
     * 3) Get all routes as a list
     * 4) Iterate through every route
     * 5) Find every service in this route
     * 6) Get a list of all buses available on the current date
     * 7) Iterate through every service
     * 8) Find a bus available for the duration of the service
     * 9) Assign the bus to this service
     */
    public ArrayList<ArrayList<Bus>> assignBuses()
    {
        //The current date used to iterate through the loop
        Calendar currentDate = (Calendar) this.startDate.clone();
        //The end date (i.e the end of the week)
        Calendar endDate = Calendar.getInstance();
        endDate.setTime(currentDate.getTime());
        endDate.add(Calendar.DAY_OF_YEAR, ROSTER_DAYS_LENGTH);
        
        //An array which will hold all the resulting buses for each day
        ArrayList<ArrayList<Bus>> returnBuses = new ArrayList<ArrayList<Bus>>();
        
        //A list of all the routes in the IBMS database
        ArrayList<Route> routes = Route.getRoutes();
        
        while (currentDate.before(endDate))
        {
            //Go through every route
            Iterator<Route> routeIter = routes.iterator();
            ArrayList<Bus> buses = Bus.getBusesAvailableOn(currentDate.getTime());
            while (routeIter.hasNext())
            {
                //Find every service in this route
                ArrayList<Service> services = Service.getAllServices
                        (routeIter.next(), currentDate, TimetableInfo.timetableKind(currentDate.getTime()));
                
                //Go through every service and assign a bus to a service
                Iterator<Service> serviceIter = services.iterator();
                while (serviceIter.hasNext())
                {
                    Service currentService = serviceIter.next();
                    int index = 0;
                    while (!currentService.isAvailableForService(buses.get(index)))
                    {
                        index++;
                        if (index >= buses.size())
                            throw new RosterException
                                    ("Could not find a bus to assign to a service! Failing with service: " 
                                    + Integer.toString(currentService.getServiceID()) + "and on day: " + currentDate.get(Calendar.DAY_OF_WEEK));
                    }
                    //Pop the currect bus from the top
                    Bus selectedBus = buses.remove(index);
                    selectedBus.addService(currentService);
                    //Append to end of the bus list (Round Robin like)
                    buses.add(selectedBus);
                    /*System.out.println("Assigning: " + buses.get(index) + " to: "
                            + currentService + "on Day: " + currentDate.get(Calendar.DAY_OF_WEEK) 
                            + " @ time:" + currentService.getEndTime().get(Calendar.HOUR) + ":" 
                            + currentService.getEndTime().get(Calendar.MINUTE));*/
                }
                
            }
            returnBuses.add(buses);
            //System.out.println("Rostered buses for day: " + Service.dayToString(currentDate));
            currentDate.add(Calendar.DAY_OF_YEAR, 1);
            progress += 10 / 1.4;

        }
        
        return returnBuses;
    }

    private static void printDrivers(ArrayList<Driver> drivers)
    {
        Iterator<Driver> iter = drivers.iterator();
    }

    public static void main(String[] args){
        database.openBusDatabase();
        /*ArrayList<Driver> drivers = new ArrayList<Driver>();
        drivers= Driver.getDrivers();
        Iterator iter = drivers.iterator();

        while(iter.hasNext())
           System.out.println(iter.next());*/


        //Roster r = new Roster();
        //r.assignBuses();
        //Calendar c = Calendar.getInstance();
        //Route r = new Route(68);
        //Service s = new Service(TimetableInfo.timetableKind.weekday, 6512, 0, r);
        //Bus b = new Bus(561);
        //s.assignBus(b);
        
        /*Calendar currentDate = Calendar.getInstance();
        ArrayList<Bus> buses = Bus.getBusesAvailableOn(currentDate.getTime());
        
        Iterator<Bus> iter = buses.iterator();
        while (iter.hasNext())
            System.out.println(iter.next());*/


       //Set people on holiday
       ArrayList<Driver> drivers = Driver.getDrivers();
       Iterator<Driver> iter = drivers.iterator();


       Calendar c = Calendar.getInstance();
       c.set(Calendar.DAY_OF_MONTH, 26);

       c.set(Calendar.HOUR_OF_DAY, 0);
       c.set(Calendar.MINUTE, 0);
       c.set(Calendar.SECOND, 0);
       c.set(Calendar.MILLISECOND, 0);
       Calendar end = (Calendar) c.clone();
       end.add(Calendar.DAY_OF_MONTH, 7);
        Calendar start = (Calendar) c.clone();
       int count = 70;
       System.out.println("Setting drivers absent on: " + Service.calendarToDateString(c));
       while (c.before(end))
       {
           while (iter.hasNext() && count > 50)
           {
               DriverInfo.setAvailable(iter.next().getDriverID(), c.getTime(), false);
               count--;
           }
           count = 70;
           c.add(Calendar.DAY_OF_MONTH, 1);
       }

       System.out.println("Drivers availble on: " + Service.calendarToDateString(start));
       ArrayList<Driver> availableDrivers = Driver.getAvailableDriversOn(start.getTime());
       Iterator<Driver> test = availableDrivers.iterator();

       int countDriver = 1;
       while (test.hasNext())
       {
           System.out.println(countDriver + ") Driver: " + test.next().getDriverID());
           countDriver++;
       }

       //Set buses unavailable
       Calendar c2 = Calendar.getInstance();
       c2.set(Calendar.HOUR_OF_DAY, 0);
       c2.set(Calendar.MINUTE, 0);
       c2.set(Calendar.SECOND, 0);
       c2.set(Calendar.MILLISECOND, 0);
       Calendar end2 = (Calendar) c2.clone();
       end2.add(Calendar.DAY_OF_MONTH, 7);

       count = 25;

       ArrayList<Bus> buses = Bus.getAllBuses();

       Iterator<Bus> busIter = buses.iterator();

       while (c2.before(end2))
       {
           while (busIter.hasNext() && count > 20)
           {
               Bus bus = busIter.next();
               BusInfo.setAvailable(bus.getBusID(), c2.getTime(), false);
               count--;
           }
           count = 25;
           c2.add(Calendar.DAY_OF_MONTH, 1);

        }
       Roster r = new Roster();
       r.generateRoster();
       /*c.set(Calendar.MONTH, 2);
       c.set(Calendar.DAY_OF_MONTH, 26);
       c.set(Calendar.HOUR, 0);
       c.set(Calendar.MINUTE, 0);
       c.set(Calendar.SECOND, 0);
       c.set(Calendar.MILLISECOND, 0);

       while (c.before(end))
       {
            ArrayList<Driver> driversAvailable = Driver.getAvailableDriversOn(c.getTime());

           iter = driversAvailable.iterator();

           System.out.println("\n\n\n");
           while (iter.hasNext())
           {
               System.out.println("Is available: " + iter.next());
           }

           c.add(Calendar.DAY_OF_YEAR, 1);
        }*/

      // System.out.println("Size: " + driversAvailable.size());
       //Roster r = new Roster();
       //r.generateRoster();
        
       //System.out.println("Size: " + returns.size());
        /*Calendar c = Calendar.getInstance();
        c.set(Calendar.DAY_OF_WEEK, 2);
        Service s = new Service(TimetableInfo.timetableKind.weekday, 6526, 13, new Route(68), c);
        
        System.out.println("Time: " + s.getStartTime().get(Calendar.HOUR) + ":" + s.getStartTime().get(Calendar.MINUTE));
        
        ArrayList<Calendar> test = s.getTimes();
        
        
        System.out.println("End Time: " + test.get(test.size() - 1).get(Calendar.HOUR) + ":" + test.get(test.size() - 1).get(Calendar.MINUTE));*/
        
        
        
        
        
        
    }



}
